﻿using System;
using System.Collections.Generic;
using System.Text;
using VIX.Enums;
using VixCOM;

namespace VIX
{
    /// <summary>
    /// Represents a Virtual Machine running on a VMware Host.
    /// </summary>
    public class VM : IDisposable
    {
        #region Private Fields
        private IVM vmHandle = null;
        private IVM2 vmHandle2 = null;
        #endregion

        #region Constructor/Destructor
        /// <summary>
        /// Initializes a new instance of the VM class. Pass the IVM handle referencing the VM as a parameter.
        /// </summary>
        /// <param name="handle">The IVM handle to the Virtual Machine.</param>
        internal VM(IVM handle)
        {
            this.vmHandle = handle;
            this.vmHandle2 = this.vmHandle as IVM2;
        }

        /// <summary>
        /// Initializes a new instance of the VM class. Pass the IVM2 handle referencing the VM as a parameter.
        /// </summary>
        /// <param name="handle">The IVM2 handle to the Virtual Machine.</param>
        internal VM(IVM2 handle)
        {
            this.vmHandle2 = handle;
            this.vmHandle = this.vmHandle2 as IVM;
        }

        /// <summary>
        /// Finalizes an instance of the VM class.
        /// </summary>
        ~VM()
        {
            Dispose();
        }

        public void Dispose()
        {
            this.vmHandle = null;
            this.vmHandle2 = null;

            GC.SuppressFinalize(this);
        }
        #endregion

        #region Properties
        /// <summary>
        /// Gets the underlying VIX-handle
        /// </summary>
        internal IVM Handle
        {
            get { return this.vmHandle; }
        }

        /// <summary>
        /// Gets the underlying VIX-handle
        /// </summary>
        internal IVM2 Handle2
        {
            get { return this.vmHandle2; }
        }
        #endregion

        #region VIX-API functions
        /// <summary>
        /// This function mounts a new shared folder in the virtual machine. 
        /// </summary>
        /// <remarks>
        /// <list type="bullet">
        /// <item>This function creates a local mount point in the guest file system and mounts a shared folder exported by the host.</item>
        /// <item>Shared folders will only be accessible inside the guest operating system if shared folders are enabled for the virtual machine. See the documentation for the <see cref="EnableSharedFolders"/> function.</item>
        /// <item>Only absolute paths should be used for files in the guest; the resolution of relative paths is not specified.</item>
        /// <item>The <paramref name="hostPathName"/> argument must specify a path to a directory that exists on the host, or an error will result.</item>
        /// <item>If a shared folder with the same name exists before calling this function, an exception with error code <see cref="VIX_E.ALREADY_EXISTS"/> will be raised.</item>
        /// <item>It is not necessary to call <see cref="LoginInGuest"/> before calling this function.</item>
        /// <item>When creating shared folders in a Windows guest, there might be a delay before contents of a shared folder are visible to functions such as <see cref="FileExistsInGuest"/> and <see cref="RunProgramInGuest"/>.</item>
        /// <item>Shared folders are not supported for the following guest operating systems: Windows ME, Windows 98, Windows 95, Windows 3.x, and DOS.</item>
        /// <item>In this release, this function requires the virtual machine to be powered on with VMware Tools installed.</item>
        /// <item>To determine in which directory in the guest the shared folder will be, query the <see cref="VIX_PROPERTY.GUEST_SHAREDFOLDERS_SHARES_PATH"/> property on the virtual machine. When the virtual machine is powered on and the VMware Tools are running, this property will contain the path to the parent directory of the shared folders for that virtual machine.</item>
        /// </list>
        /// </remarks>      
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="shareName">Specifies the guest path name of the new shared folder.</param>
        /// <param name="hostPathName">Specifies the host path of the shared folder.</param>
        public void AddSharedFolder(string shareName, string hostPathName)
        {
            IJob jobHandle = this.vmHandle.AddSharedFolder(shareName, hostPathName, VixCOM.Constants.VIX_SHAREDFOLDER_WRITE_ACCESS, null);
            JobWaitWithoutResults(jobHandle);
        }

        /// <summary>
        /// This function records a virtual machine's activity as a snapshot object. The snapshot object is returned in the job object's properties.
        /// </summary>
        /// <remarks>
        /// <list type="bullet">
        /// <item>Record-replay functionality has been deprecated and this function may be removed from future versions of the VIX API.</item>
        /// <item>The virtual machine must be powered on. To record the virtual machine from the beginning, call <see cref="PowerOn(VIX_VMPOWEROP)"/> with <see cref="VIX_VMPOWEROP.START_VM_PAUSED"/>, then start recording.</item>
        /// <item>This function only works on a virtual machine that is not already recording or replaying.</item>
        /// <item>If recording name is <c>null</c>, creates a snapshot object with no name.</item>
        /// <item>This function is not supported when using the <see cref="VIX_SERVICEPROVIDER.VMWARE_PLAYER"/> host type.</item>
        /// </list>
        /// Side effects:
        /// This function disrupts communication with VMware Tools. Any outstanding Vix related guest operation may be aborted. Users will need to call <see cref="WaitForToolsInGuest"/> before performing additional operations in the guest.
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="name">A user-defined name for the recording; need not be unique.</param>
        /// <param name="description">A user-defined description for the recording.</param>
        /// <returns>A <see cref="Snapshot"/> object needed to replay the recording.</returns>
        [Obsolete]
        public Snapshot BeginRecording(string name, string description)
        {
            IJob jobHandle = this.vmHandle2.BeginRecording(name, description, 0, null, null);
            object results = null;
            ulong err = jobHandle.Wait(new VIX_PROPERTY[] { VIX_PROPERTY.JOB_RESULT_HANDLE }, ref results);
            VixCOMWrapper.Instance.CheckForError(err);
            return new Snapshot((ISnapshot)((object[])results)[0]);
        }

        /// <summary>
        /// This function replays a recording of a virtual machine.
        /// </summary>
        /// <remarks>
        /// <list type="bullet">
        /// <item>Record-replay functionality has been deprecated and this function may be removed from future versions of the VIX API.</item>
        /// <item>Use of this function with a non-recording snapshot raises an exception with an error code of <see cref="VIX_E.INVALID_ARG"/>.</item>
        /// <item>To display playback of the recording with the Workstation user interface, <paramref name="powerOnOptions"/> must have the <see cref="VIX_VMPOWEROP.LAUNCH_GUI"/> flag. If there is an existing instance of the Workstation user interface, the virtual machine will power on in a new tab within that instance. Otherwise, a new instance of Workstation will open, and the virtual machine will power on there.</item>
        /// <item>Guest commands are not allowed while the virtual machine is replaying a recording.</item>
        /// <item>Once the recording has finished, the virtual machine will automatically "go live"; it will resume normal execution from the last state that is part of the recording.</item>
        /// <item>The property <see cref="VIX_PROPERTY.SNAPSHOT_IS_REPLAYABLE"/> can be used to determine if a snapshot is a recording.</item>
        /// <item>This function is not supported when using the <see cref="VIX_SERVICEPROVIDER.VMWARE_PLAYER"/> host type.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <exception cref="ArgumentException">Thrown when <paramref name="powerOnOptions"/> is not <see cref="VIX_VMPOWEROP.NORMAL"/> or <see cref="VIX_VMPOWEROP.LAUNCH_GUI"/>.</exception>
        /// <param name="recording">Snapshot object that represents the recording</param>
        /// <param name="powerOnOptions">Must be <see cref="VIX_VMPOWEROP.NORMAL"/> or <see cref="VIX_VMPOWEROP.LAUNCH_GUI"/>.</param>
        [Obsolete]
        public void BeginReplay(Snapshot recording, VIX_VMPOWEROP powerOnOptions)
        {
            if (!(powerOnOptions == VIX_VMPOWEROP.NORMAL || powerOnOptions == VIX_VMPOWEROP.LAUNCH_GUI))
                throw new ArgumentException("The powerOnOptions argument has to be either VIX_VMPOWEROP.NORMAL or VIX_VMPOWEROP.LAUNCH_GUI.");

            IJob jobHandle = this.vmHandle2.BeginReplay(recording.Handle, (int)powerOnOptions, null, null);
            JobWaitWithoutResults(jobHandle);
        }

        /// <summary>
        /// This function captures the screen of the guest operating system. 
        /// </summary>
        /// <remarks>
        /// <list type="bullet">
        /// <item>For security reasons, this function requires a successful call to <see cref="LoginInGuest"/> must be made.</item>
        /// </list>
        /// </remarks>
        /// <overloads>This method has one overload. Check <see cref="CaptureScreenImage(string)"/> for details.</overloads>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <returns>A <see cref="System.Drawing.Image"/> object holding the captured screen image.</returns>
        public System.Drawing.Image CaptureScreenImage()
        {
            IJob jobHandle = this.vmHandle2.CaptureScreenImage(VixCOM.Constants.VIX_CAPTURESCREENFORMAT_PNG, null, null);

            object results = null;

            ulong err = jobHandle.Wait(new VIX_PROPERTY[] { VIX_PROPERTY.JOB_RESULT_SCREEN_IMAGE_DATA }, ref results);

            VixCOMWrapper.Instance.CheckForError(err);

            byte[] arrayOfImageBytes = (byte[])((object[])results)[0];

            System.IO.MemoryStream ms = new System.IO.MemoryStream(arrayOfImageBytes);
            System.Drawing.Image returnImage = System.Drawing.Image.FromStream(ms);

            return returnImage;
        }

        /// <summary>
        /// This function captures the screen of the guest operating system. 
        /// </summary>
        /// <remarks>
        /// <list type="bullet">
        /// <item>For security reasons, this function requires a successful call to <see cref="LoginInGuest"/> must be made.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="filePath">Path where the file should be saved.</param>
        public void CaptureScreenImage(string filePath)
        {
            this.CaptureScreenImage().Save(filePath);
        }

        /// <summary>
        /// Creates a copy of the virtual machine based off the current state of the virtual machine.
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>It is not possible to create a full clone of a powered on virtual machine. You must power off or suspend a virtual machine before creating a full clone of that machine.</item>
        /// <item>With a suspended virtual machine, requesting a linked clone results in an exception with error-code <see cref="VIX_E.VM_IS_RUNNING"/>. Suspended virtual machines retain memory state, so proceeding with a linked clone could cause loss of data.</item>
        /// <item>A linked clone must be based on a virtual machine's snapshot. A new snapshot will be created by the function. This snapshot will reflect the current state of the virtual machine and will be used as a basis for the linked clone.</item>
        /// <item>A linked clone must have access to the parent's virtual disks. Without such access, you cannot use a linked clone at all because its file system will likely be incomplete or corrupt.</item>
        /// <item>Deleting a virtual machine that is the parent of a linked clone renders the linked clone useless.</item>
        /// <item>Because a full clone does not share virtual disks with the parent virtual machine, full clones generally perform better than linked clones. However, full clones take longer to create than linked clones. Creating a full clone can take several minutes if the files involved are large.</item>
        /// <item>This function is not supported when using the <see cref="VIX_SERVICEPROVIDER.VMWARE_PLAYER"/> host type.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="cloneType">Must be either <see cref="VIX_CLONETYPE.FULL"/> or <see cref="VIX_CLONETYPE.LINKED"/>. VIX_CLONETYPE_FULL - Creates a full, independent clone of the virtual machine. VIX_CLONETYPE_LINKED - Creates a linked clone, which is a copy of a virtual machine that shares virtual disks with the parent virtual machine in an ongoing manner. This conserves disk space as long as the parent and clone do not change too much from their original state.</param>
        /// <param name="destConfigPathName">The path name of the virtual machine configuration file that will be created for the virtual machine clone produced by this operation. This should be a full absolute path name, with directory names delineated according to host system convention: \ for Windows and / for Linux.</param>
        /// <returns>A <see cref="VM"/> object providing access to the copy of the VM.</returns>
        public VM Clone(VIX_CLONETYPE cloneType, string destConfigPathName)
        {
            return this.Clone(null, cloneType, destConfigPathName);
        }

        /// <summary>
        /// Creates a copy of the virtual machine based off the state when a snapshot was taken.
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>It is not possible to create a full clone of a powered on virtual machine. You must power off or suspend a virtual machine before creating a full clone of that machine.</item>
        /// <item>With a suspended virtual machine, requesting a linked clone results in an exception with error-code <see cref="VIX_E.VM_IS_RUNNING"/>. Suspended virtual machines retain memory state, so proceeding with a linked clone could cause loss of data.</item>
        /// <item>A linked clone must be based on a virtual machine's snapshot. If a clone of this type is requested and <c>null</c> is passed as the <paramref name="snapshot"/> parameter, a new snapshot will be created by the function. This snapshot will reflect the current state of the virtual machine and will be used as a basis for the linked clone.</item>
        /// <item>A linked clone must have access to the parent's virtual disks. Without such access, you cannot use a linked clone at all because its file system will likely be incomplete or corrupt.</item>
        /// <item>Deleting a virtual machine that is the parent of a linked clone renders the linked clone useless.</item>
        /// <item>Because a full clone does not share virtual disks with the parent virtual machine, full clones generally perform better than linked clones. However, full clones take longer to create than linked clones. Creating a full clone can take several minutes if the files involved are large.</item>
        /// <item>This function is not supported when using the <see cref="VIX_SERVICEPROVIDER.VMWARE_PLAYER"/> host type.</item>        
        /// </list>
        /// </remarks>
        /// Side effects:
        /// If the <paramref name="cloneType"></paramref> parameter is <see cref="VIX_CLONETYPE.LINKED"/> and the <paramref name="snapshot"></paramref> parameter is <c>null</c>, then the function will create a snapshot of the current virtual machine state and use that to created the linked clone. 
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="snapshot">A snapshot belonging to this virtual machine. The clone will be a copy of the state of the virtual machine at the time the snapshot was taken. If you pass <c>null</c> the clone will be based off the current state of the virtual machine.</param>
        /// <param name="cloneType">Must be either <see cref="VIX_CLONETYPE.FULL"/> or <see cref="VIX_CLONETYPE.LINKED"/>. VIX_CLONETYPE_FULL - Creates a full, independent clone of the virtual machine. VIX_CLONETYPE_LINKED - Creates a linked clone, which is a copy of a virtual machine that shares virtual disks with the parent virtual machine in an ongoing manner. This conserves disk space as long as the parent and clone do not change too much from their original state.</param>
        /// <param name="destConfigPathName">The path name of the virtual machine configuration file that will be created for the virtual machine clone produced by this operation. This should be a full absolute path name, with directory names delineated according to host system convention: \ for Windows and / for Linux.</param>
        /// <returns>A <see cref="VM"/> object providing access to the copy of the VM.</returns>
        public VM Clone(Snapshot snapshot, VIX_CLONETYPE cloneType, string destConfigPathName)
        {
            IJob jobHandle = this.vmHandle2.Clone(snapshot == null ? null : snapshot.Handle, (int)cloneType, destConfigPathName, 0, null, null);

            object results = null;

            ulong err = jobHandle.Wait(new VIX_PROPERTY[] { VIX_PROPERTY.JOB_RESULT_HANDLE }, ref results);
            VixCOMWrapper.Instance.CheckForError(err);

            VM res = new VM((IVM2)((object[])results)[0]);
            return res;
        }

        /// <summary>
        /// Copies a file or directory from the guest operating system to the local system (where the Vix client is running). 
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>This function copies a file from the guest operating system to the Vix client machine. The virtual machine must be running while the file is copied.</item>
        /// <item>Only absolute paths should be used for files in the guest; the resolution of relative paths is not specified.</item>
        /// <item>You must call <see cref="LoginInGuest"/> before calling this procedure.</item>
        /// <item>The format of the file name depends on the guest or local operating system. For example, a path name for a Microsoft Windows guest or host requires backslash as a directory separator, whereas a Linux guest or host requires a forward slash. In C#, if the path name includes backslash characters, you need to precede each one with an escape character (as in "C:\\temp\\file.dat"). Escape characters are not needed in VB or VBScript.</item>
        /// <item>The copy operation requires VMware Tools to be installed and running in the guest operating system.</item>
        /// <item>If any file fails to be copied, the operation returns an error. In this case, Vix aborts the operation and does not attempt to copy the remaining files.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="guestPathName">The path name of a file on a file system available to the guest.</param>
        /// <param name="hostPathName">The path name of a file on a file system available to the Vix client.</param>
        public void CopyFileFromGuestToHost(string guestPathName, string hostPathName)
        {
            IJob jobHandle = this.vmHandle.CopyFileFromGuestToHost(guestPathName, hostPathName, 0, null, null);
            JobWaitWithoutResults(jobHandle);
        }

        /// <summary>
        /// Copies a file or directory from the local system (where the Vix client is running) to the guest operating system. 
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>This function copies a file from the Vix client machine is running to the guest operating system. The virtual machine must be running while the file is copied.</item>
        /// <item>Only absolute paths should be used for files in the guest; the resolution of relative paths is not specified.</item>
        /// <item>The format of the file name depends on the guest or local operating system. For example, a path name for a Microsoft Windows guest or host requires backslash as a directory separator, whereas a Linux guest or host requires a forward slash. In C#, if the path name includes backslash characters, you need to precede each one with an escape character (as in "C:\\temp\\file.dat"). Escape characters are not needed in VB or VBScript.</item>
        /// <item>You must call <see cref="LoginInGuest"/> before calling this function.</item>
        /// <item>The copy operation requires VMware Tools to be installed and running in the guest operating system.</item>
        /// <item>If any file fails to be copied, the operation returns an error. In this case, Vix aborts the operation and does not attempt to copy the remaining files.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="hostPathName">The path name of a file on a file system available to the Vix client.</param>
        /// <param name="guestPathName">The path name of a file on a file system available to the guest.</param>
        public void CopyFileFromHostToGuest(string hostPathName, string guestPathName)
        {
            IJob jobHandle = this.vmHandle.CopyFileFromHostToGuest(hostPathName, guestPathName, 0, null, null);
            JobWaitWithoutResults(jobHandle);
        }

        /// <summary>
        /// This function creates a directory in the guest operating system.
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>You must call <see cref="LoginInGuest"/> before calling this function.</item>
        /// <item>If the parent directories for the specified path do not exist, this function will create them.</item>
        /// <item>If the directory already exists, an exception with the error-code <see cref="VIX_E.FILE_ALREADY_EXISTS"/> will be raised.</item>
        /// <item>Only absolute paths should be used for files in the guest; the resolution of relative paths is not specified.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="pathName">The path to the directory to be created.</param>
        public void CreateDirectoryInGuest(string pathName)
        {
            IJob jobHandle = this.vmHandle.CreateDirectoryInGuest(pathName, null, null);
            JobWaitWithoutResults(jobHandle);
        }

        /// <summary>
        /// This method saves a copy of the virtual machine state as a <see cref="Snapshot"/> object.
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>This function creates a child snapshot of the current snapshot.</item>
        /// <item>If a virtual machine is suspended, you cannot snapshot it more than once.</item>
        /// <item>If a powered-on virtual machine gets a snapshot created with <paramref name="includeMemory"/> set to false, the power state is not saved, so reverting to the snapshot sets powered-off state.</item>
        /// <item>The <paramref name="name"/> and <paramref name="description"/> parameters can be set but not retrieved using the VIX API. </item>
        /// <item>VMware Server supports only a single snapshot for each virtual machine. The following considerations apply to VMware Server:</item>
        /// * If you call this function a second time for the same virtual machine without first deleting the snapshot, the second call will overwrite the previous snapshot.
        /// * A virtual machine imported to VMware Server from another VMware product might have more than one snapshot at the time it is imported. In that case, you can use this function to add a new snapshot to the series.
        /// <item>The <paramref name="name"/> and <paramref name="description"/> parameters can be set but not retrieved using the VIX API.</item>
        /// <item>Starting in VMware Workstation 6.5, snapshot operations are allowed on virtual machines that are part of a team. Previously, this operation failed with error code <see cref="VIX_PROPERTY.VM_IN_VMTEAM"/>. Team members snapshot independently so they can have different and inconsistent snapshot states.</item>
        /// <item>This function is not supported when using the <see cref="VIX_SERVICEPROVIDER.VMWARE_PLAYER"/> host type.</item>
        /// <item>If the virtual machine is open and powered off in the UI, this function now closes the virtual machine in the UI before creating the snapshot. </item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="name">A user-defined name for the snapshot; need not be unique.</param>
        /// <param name="description">A user-defined description for the snapshot.</param>
        /// <param name="includeMemory">Captures the full state of a running virtual machine, including the memory.</param>
        /// <returns>A <see cref="Snapshot"/> object representing the snapshot created.</returns>
        public Snapshot CreateSnapshot(string name, string description, bool includeMemory)
        {
            IJob jobHandle = this.vmHandle.CreateSnapshot(name, description, includeMemory ? VixCOM.Constants.VIX_SNAPSHOT_INCLUDE_MEMORY : 0, null, null);

            object foundProperties = null;

            ulong err = jobHandle.Wait(new VIX_PROPERTY[] { VIX_PROPERTY.JOB_RESULT_HANDLE }, ref foundProperties);
            VixCOMWrapper.Instance.CheckForError(err);

            ISnapshot snapshotH = (ISnapshot)((object[])foundProperties)[0];
            return new Snapshot(snapshotH);
        }

        /// <summary>
        /// This function creates a temporary file in the guest operating system.
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>You must call <see cref="LoginInGuest"/> before calling this function.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <returns>The path to the created temporary file.</returns>
        public string CreateTempFileInGuest()
        {
            IJob jobHandle = this.vmHandle.CreateTempFileInGuest(0, null, null);
            object results = null;
            ulong err = jobHandle.Wait(new VIX_PROPERTY[] { VIX_PROPERTY.JOB_RESULT_ITEM_NAME }, ref results);
            VixCOMWrapper.Instance.CheckForError(err);
            return (string)((object[])results)[0];
        }

        /// <summary>
        /// This function permanently deletes a virtual machine from your host system. 
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>This function permanently deletes a virtual machine from your host system. You can accomplish the same effect by deleting all virtual machine files using the host file system. This function simplifies the task by deleting all VMware files in a single function call. This function does not delete other user files in the virtual machine folder.</item>
        /// <item>This function is successful only if the virtual machine is powered off or suspended.</item>
        /// <item>Deleting a virtual machine that is the parent of a linked clone renders the linked clone useless.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="deleteDiskFiles">For VMware Server 2.0 and ESX, this value must be true. For all other versions it can be either true or false. When option is true, deletes all associated files. When option is false, does not delete *.vmdk virtual disk file(s).</param>
        public void Delete(bool deleteDiskFiles)
        {
            IJob jobHandle = this.vmHandle.Delete(deleteDiskFiles ? VixCOM.Constants.VIX_VMDELETE_DISK_FILES : 0, null);
            JobWaitWithoutResults(jobHandle);
        }

        /// <summary>
        /// This function deletes a directory in the guest operating system. Any files or subdirectories in the specified directory will also be deleted.
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>You must call <see cref="LoginInGuest"/> before calling this function.</item>
        /// <item>Only absolute paths should be used for files in the guest; the resolution of relative paths is not specified.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="pathName">The path to the directory to be deleted.</param>
        public void DeleteDirectoryInGuest(string pathName)
        {
            IJob jobHandle = this.vmHandle.DeleteDirectoryInGuest(pathName, 0, null);
            JobWaitWithoutResults(jobHandle);
        }

        /// <summary>
        /// This function deletes a file in the guest operating system. 
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>You must call <see cref="LoginInGuest"/> before calling this function.</item>
        /// <item>Only absolute paths should be used for files in the guest; the resolution of relative paths is not specified.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="pathName">The path to the file to be deleted.</param>
        public void DeleteFileInGuest(string pathName)
        {
            IJob jobHandle = this.vmHandle.DeleteFileInGuest(pathName, null);
            JobWaitWithoutResults(jobHandle);
        }

        /// <summary>
        /// This function tests the existence of a directory in the guest operating system. 
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>You must call <see cref="LoginInGuest"/> before calling this function.</item>
        /// <item>Only absolute paths should be used for files in the guest; the resolution of relative paths is not specified.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="pathName">The path to the directory in the guest to be checked.</param>
        /// <returns>True if the directory exists, otherwise false.</returns>
        public bool DirectoryExistsInGuest(string pathName)
        {
            IJob jobHandle = this.vmHandle.DirectoryExistsInGuest(pathName, null);
            object results = null;
            ulong err = jobHandle.Wait(new VIX_PROPERTY[] { VIX_PROPERTY.JOB_RESULT_GUEST_OBJECT_EXISTS }, ref results);
            VixCOMWrapper.Instance.CheckForError(err);
            return (bool)((object[])results)[0];
        }

        /// <summary>
        /// This function enables or disables all shared folders as a feature for a virtual machine. 
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>This function enables/disables all shared folders as a feature on a virtual machine. In order to access shared folders on a guest, the feature has to be enabled, and in addition, the individual shared folder has to be enabled.</item>
        /// <item>It is not necessary to call <see cref="LoginInGuest"/> before calling this function.</item>
        /// <item>In this release, this function requires the virtual machine to be powered on with VMware Tools installed.</item>
        /// <item>Shared folders are not supported for the following guest operating systems: Windows ME, Windows 98, Windows 95, Windows 3.x, and DOS.</item>
        /// <item></item>
        /// Side effects:
        /// On Linux virtual machines, calling this function will automatically mount shared folder(s) in the guest.
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="enabled">Pass true if enabling shared folders is desired. Pass false otherwise.</param>
        public void EnableSharedFolders(bool enabled)
        {
            IJob jobHandle = this.vmHandle.EnableSharedFolders(enabled, 0, null);
            JobWaitWithoutResults(jobHandle);
        }

        /// <summary>
        /// This function stops recording a virtual machine's activity.
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>Record-replay functionality has been deprecated and this function may be removed from future versions of the VIX API.</item>
        /// <item>This operation only works on a virtual machine that is recording.</item>
        /// <item>This function is not supported when using the <see cref="VIX_SERVICEPROVIDER.VMWARE_PLAYER"/> host type.</item>
        /// </list>
        /// Side effects:
        /// This function disrupts communication with VMware Tools. Any outstanding Vix related guest operation may be aborted. Users will need to call <see cref="WaitForToolsInGuest"/> before performing additional operations in the guest.
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        [Obsolete]
        public void EndRecording()
        {
            IJob jobHandle = this.vmHandle2.EndRecording(0, null, null);
            JobWaitWithoutResults(jobHandle);
        }

        /// <summary>
        /// This function stops replaying a virtual machine's recording. 
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>Record-replay functionality has been deprecated and this function may be removed from future versions of the VIX API.</item>
        /// <item>This operation only works on a virtual machine that is replaying.</item>
        /// <item>This function will cause the virtual machine to "go live"; it will resume normal execution, continuing on from the last state that was replayed from the recording.</item>
        /// <item>This function is not supported when using the <see cref="VIX_SERVICEPROVIDER.VMWARE_PLAYER"/> host type.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        [Obsolete]
        public void EndReplay()
        {
            IJob jobHandle = this.vmHandle2.EndReplay(0, null, null);
            JobWaitWithoutResults(jobHandle);
        }

        /// <summary>
        /// This function tests the existence of a file in the guest operating system.
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>You must call <see cref="LoginInGuest"/> before calling this function.</item>
        /// <item>Only absolute paths should be used for files in the guest; the resolution of relative paths is not specified.</item>
        /// <item>If <paramref name="guestPathName"/> exists as a file system object, but is not a normal file (e.g. it is a directory, device, UNIX domain socket, etc), then false is returned.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="guestPathName">The path to the file to be tested.</param>
        /// <returns>True if file exists. False otherwise.</returns>
        public bool FileExistsInGuest(string guestPathName)
        {
            IJob jobHandle = this.vmHandle.FileExistsInGuest(guestPathName, null);
            object results = null;
            ulong err = jobHandle.Wait(new VIX_PROPERTY[] { VIX_PROPERTY.JOB_RESULT_GUEST_OBJECT_EXISTS }, ref results);
            VixCOMWrapper.Instance.CheckForError(err);
            return (bool)((object[])results)[0];
        }

        /// <summary>
        /// This function returns the current active snapshot belonging to this VM.
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>This function is not supported when using the <see cref="VIX_SERVICEPROVIDER.VMWARE_PLAYER"/> host type.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <returns>A <see cref="Snapshot"/> object to the current snapshot of this VM.</returns>
        public Snapshot GetCurrentSnapshot()
        {
            ISnapshot childSnapshot;
            ulong err = this.vmHandle.GetCurrentSnapshot(out childSnapshot);
            VixCOMWrapper.Instance.CheckForError(err);
            return new Snapshot(childSnapshot);
        }

        /// <summary>
        /// This function returns information about a file in the guest operating system. 
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>You must call <see cref="LoginInGuest"/> before calling this function.</item>
        /// <item>Only absolute paths should be used for files in the guest; the resolution of relative paths is not specified.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>      
        /// <param name="filePath">The path name of the file in the guest.</param>
        /// <returns>A <see cref="GuestFileInfo"/> object holding information about the file.</returns>
        public GuestFileInfo GetFileInfoInGuest(string filePath)
        {
            IJob jobHandle = this.vmHandle2.GetFileInfoInGuest(filePath, null);
            object results = null;
            ulong err = jobHandle.Wait(new VIX_PROPERTY[] { VIX_PROPERTY.JOB_RESULT_FILE_SIZE, VIX_PROPERTY.JOB_RESULT_FILE_MOD_TIME, VIX_PROPERTY.JOB_RESULT_FILE_FLAGS }, ref results);
            VixCOMWrapper.Instance.CheckForError(err);

            GuestFileInfo res = new GuestFileInfo(
                // file size 
                (long)((object[])results)[0],
                // modification date in seconds from 1st January 1970
                new DateTime(1970, 1, 1).AddSeconds((long)((object[])results)[1]),
                // file attribute flags
                (VIX_FILE_ATTRIBUTES)((object[])results)[2]);

            return res;
        }

        /// <summary>
        /// This method returns a <see cref="Snapshot"/> object referencing a snapshot matching the given name in the virtual machine. 
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>This function returns a <see cref="Snapshot"/> object referencing a snapshot with matching name.</item>
        /// <item>When the snapshot name is a duplicate, an exception with error-code <see cref="VIX_E.SNAPSHOT_NONUNIQUE_NAME"/> will be raised.</item>
        /// <item>You can specify the snapshot name as a path using '/' or '\\' as path separators, including snapshots in the tree above the named snapshot, for example 'a/b/c' or 'x/x'. Do not mix '/' and '\\' in the same path expression.</item>
        /// <item>This function is not supported when using the <see cref="VIX_SERVICEPROVIDER.VMWARE_PLAYER"/> host type.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="snapshotName">Identifies a snapshot name.</param>
        /// <returns>A <see cref="Snapshot"/> object for the named snapshot.</returns>
        public Snapshot GetNamedSnapshot(string snapshotName)
        {
            ISnapshot snapshot;
            ulong err = this.vmHandle.GetNamedSnapshot(snapshotName, out snapshot);
            VixCOMWrapper.Instance.CheckForError(err);
            return new Snapshot(snapshot);
        }

        /// <summary>
        /// This function returns the number of top-level (root) snapshots belonging to this virtual machine. 
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>This function returns the number of top-level (root) snapshots belonging to a virtual machine. A top-level snapshot is one that is not based on any previous snapshot. If the virtual machine has more than one snapshot, the snapshots can be a sequence in which each snapshot is based on the previous one, leaving only a single top-level snapshot. However, if applications create branched trees of snapshots, a single virtual machine can have several top-level snapshots.</item>
        /// <item>VMware Server can manage only a single snapshot for each virtual machine. All other snapshots in a sequence are ignored. The value of the result parameter is always 0 or 1.</item>
        /// <item>This function is not supported when using the <see cref="VIX_SERVICEPROVIDER.VMWARE_PLAYER"/> host type.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <returns>The number of root snapshots on this virtual machine.</returns>
        public int GetNumRootSnapshots()
        {
            int result;
            ulong err = this.vmHandle.GetNumRootSnapshots(out result);
            VixCOMWrapper.Instance.CheckForError(err);
            return result;
        }

        /// <summary>
        /// This function returns the number of shared folders mounted in the virtual machine. 
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>It is not necessary to call <see cref="LoginInGuest"/> before calling this function.</item>
        /// <item>Shared folders are not supported for the following guest operating systems: Windows ME, Windows 98, Windows 95, Windows 3.x, and DOS.</item>
        /// <item>In this release, this function requires the virtual machine to be powered on with VMware Tools installed.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <returns>The number of shared folders mounted in the virtual machine.</returns>
        public int GetNumSharedFolders()
        {
            IJob jobHandle = this.vmHandle.GetNumSharedFolders(null);
            object results = null;
            ulong err = jobHandle.Wait(new VIX_PROPERTY[] { VIX_PROPERTY.JOB_RESULT_SHARED_FOLDER_COUNT }, ref results);
            VixCOMWrapper.Instance.CheckForError(err);
            return (int)((object[])results)[0];
        }

        /// <summary>
        /// This method allows you to get one or more properties from the VM. For a list of property IDs, see <see cref="VIX_PROPERTY"/>.
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>This function allows you to get one or more properties from the VM, but only specific properties may be defined for this object.</item>
        /// <item>The value of <see cref="VIX_PROPERTY.VM_TOOLS_STATE"/> is valid only after calling <see cref="WaitForToolsInGuest"/>.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="propertyIDs">An array of property-IDs to identify the properties to fetch.</param>
        /// <returns>A <see cref="System.Collections.Generic.List{T}"/> object that stores the properties identified by the array <paramref name="propertyIDs"/>. Each element in <paramref name="propertyIDs"/> matches the corresponding indentifier in the returned <see cref="System.Collections.Generic.List{T}"/>; for example, if the first element in the <paramref name="propertyIDs"/> array is <see cref="VIX_PROPERTY.VM_IS_RUNNING"/>, the first element in the <see cref="System.Collections.Generic.List{T}"/> will be the object that is the result of this job, if one exists.</returns>
        public List<object> GetProperties(VIX_PROPERTY[] propertyIDs)
        {
            return VixCOMWrapper.Instance.GetProperties((IVixHandle)this.vmHandle, propertyIDs);
        }

        /// <summary>
        /// This function returns the specified snapshot belonging to the virtual machine. 
        /// </summary>
        /// <remarks>
        /// <list type="bullet">
        /// <item>Snapshots are indexed from 0 to n-1, where n is the number of root snapshots. Use the function <see cref="GetNumRootSnapshots"/> to get the value of n.</item>
        /// <item>VMware Server can manage only a single snapshot for each virtual machine. The value of index can only be 0.</item>
        /// <item>This function is not supported when using the <see cref="VIX_SERVICEPROVIDER.VMWARE_PLAYER"/> host type.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="index">Identifies a root snapshot. See remarks for range of values.</param>
        /// <returns>Returns a <see cref="Snapshot"/> object representing the root snapshot.</returns>
        public Snapshot GetRootSnapshot(int index)
        {
            ISnapshot snapshot;

            ulong err = this.vmHandle.GetRootSnapshot(index, out snapshot);

            VixCOMWrapper.Instance.CheckForError(err);

            return new Snapshot(snapshot);
        }

        /// <summary>
        /// This function returns the state of a shared folder mounted in the virtual machine. 
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>Shared folders are indexed from 0 to n-1, where n is the number of shared folders. Use the function <see cref="GetNumSharedFolders"/> to get the value of n.</item>
        /// <item>It is not necessary to call <see cref="LoginInGuest"/> before calling this function.</item>
        /// <item>Shared folders are not supported for the following guest operating systems: Windows ME, Windows 98, Windows 95, Windows 3.x, and DOS.</item>
        /// <item>In this release, this function requires the virtual machine to be powered on with VMware Tools installed.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="index">Identifies the shared folder.</param>
        /// <returns>Returns an array of objects holding the state of a shared folder mounted in the virtual machine. Index 0 contains the name of the folder, 1 the host path its mounted from and 2 the flags describing the folder options.</returns>
        public object[] GetSharedFolderState(int index)
        {
            IJob jobHandle = this.vmHandle.GetSharedFolderState(index, null);
            JobWaitWithoutResults(jobHandle);

            List<object> temp = VixCOMWrapper.Instance.GetProperties((IVixHandle)jobHandle, new VIX_PROPERTY[] { VIX_PROPERTY.JOB_RESULT_ITEM_NAME, VIX_PROPERTY.JOB_RESULT_SHARED_FOLDER_HOST, VIX_PROPERTY.JOB_RESULT_SHARED_FOLDER_FLAGS });

            return temp.ToArray();
        }

        /// <summary>
        /// Prepares to install VMware Tools on the guest operating system.
        /// </summary>
        /// <remarks>
        /// <list type="bullet">
        /// <item>If the option <see cref="VIX_INSTALLTOOLS.MOUNT_TOOLS_INSTALLER"/> is provided, the function prepares an ISO image to install VMware Tools on the guest operating system. If autorun is enabled, as it often is on Windows, installation begins, otherwise you must initiate installation. If VMware Tools is already installed, this function prepares to upgrade it to the version matching the product.</item>
        /// <item>If the option <see cref="VIX_INSTALLTOOLS.AUTO_UPGRADE"/> is provided, the function attempts to automatically upgrade VMware Tools without any user interaction required, and then reboots the virtual machine. This option requires that a version of VMware Tools already be installed. If VMware Tools is not already installed, the function will fail.</item>
        /// <item>When the option <see cref="VIX_INSTALLTOOLS.AUTO_UPGRADE"/> is used on virtual machine with a Windows guest operating system, the upgrade process may cause the Windows guest to perform a controlled reset in order to load new device drivers. If you intend to perform additional guest operations after upgrading the VMware Tools, it is recommanded that after this task completes, that the guest be reset using <see cref="Reset"/> with the <see cref="VIX_VMPOWEROP.FROM_GUEST"/> flag, followed by calling <see cref="WaitForToolsInGuest"/> to ensure that the guest has reached a stable state.</item>
        /// <item>If the <see cref="VIX_INSTALLTOOLS.RETURN_IMMEDIATELY"/> flag is set, this function will report completion to the IJob object immediately after mounting the VMware Tools ISO image.</item>
        /// <item>If the <see cref="VIX_INSTALLTOOLS.RETURN_IMMEDIATELY"/> flag is not set for an ESX host, this function will report completion to the IJob object immediately after mounting the VMware Tools ISO image.</item>
        /// <item>If the <see cref="VIX_INSTALLTOOLS.RETURN_IMMEDIATELY"/> flag is not set for a WS host, this function will report completion to the IJob object only after the installation successfully completes or is cancelled.</item>
        /// <item>The virtual machine must be powered on to do this operation.</item>
        /// <item>If the Workstation installer calls for an ISO file that is not downloaded, this function returns an error, rather than attempting to download the ISO file.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="options">May be either <see cref="VIX_INSTALLTOOLS.MOUNT_TOOLS_INSTALLER"/> or <see cref="VIX_INSTALLTOOLS.AUTO_UPGRADE"/>. Either flag can be combined with the <see cref="VIX_INSTALLTOOLS.RETURN_IMMEDIATELY"/> flag using the bitwise inclusive OR operator (|). See remarks for more information.</param>
        public void InstallTools(VIX_INSTALLTOOLS options)
        {
            IJob jobHandle = this.vmHandle.InstallTools((int)options, null, null);
            JobWaitWithoutResults(jobHandle);
        }

        /// <summary>
        /// This function terminates a process in the guest operating system. 
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>You must call <see cref="LoginInGuest"/> before calling this function.</item>
        /// <item>Depending on the behavior of the guest operating system, there may be a short delay after the job completes before the process truly disappears.</item>
        /// <item>Because of differences in how various Operating Systems handle process IDs, Vix may raise an exception with either <see cref="VIX_E.INVALID_ARG"/> or <see cref="VIX_E.NO_SUCH_PROCESS"/> for invalid process IDs.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="pid">The ID of the process to be killed.</param>
        public void KillProcessInGuest(ulong pid)
        {
            IJob jobHandle = this.vmHandle.KillProcessInGuest(pid, 0, null);
            JobWaitWithoutResults(jobHandle);
        }

        /// <summary>
        /// This function lists a directory in the guest operating system.
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>You must call <see cref="LoginInGuest"/> before calling this function.</item>
        /// <item>Only absolute paths should be used for files in the guest; the resolution of relative paths is not specified.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="pathName">The path name of a directory to be listed.</param>
        /// <returns>A list of <see cref="GuestFileOrDirectory"/> objects containing information about every file or directory in the directory.</returns>
        public List<GuestFileOrDirectory> ListDirectoryInGuest(string pathName)
        {
            IJob jobHandle = this.vmHandle.ListDirectoryInGuest(pathName, 0, null);
            JobWaitWithoutResults(jobHandle);

            List<object> list = VixCOMWrapper.Instance.GetProperties((IVixHandle)jobHandle, new VIX_PROPERTY[] { VIX_PROPERTY.JOB_RESULT_ITEM_NAME, VIX_PROPERTY.JOB_RESULT_FILE_FLAGS, VIX_PROPERTY.JOB_RESULT_FILE_MOD_TIME });

            List<GuestFileOrDirectory> res = new List<GuestFileOrDirectory>();

            int parCount = ((object[])list[0]).Length;

            // Index 0 contains the file name, 1 the file attribute flags and 2 the modification time of the file or directory as a 64-bit integer.
            for (int i = 0; i < parCount; i++)
                res.Add(new GuestFileOrDirectory(
                    // file name
                    (string)((object[])list[0])[i],
                    // modification time in seconds since 1st January 1970
                    new DateTime(1970, 1, 1).AddSeconds((long)((object[])list[2])[i]),
                    // file attribute flags, if 0 the item is a file otherwise it's a directory
                    ((int)((object[])list[1])[i] == 1) ? true : false));

            return res;
        }

        /// <summary>
        /// This function lists the running processes in the guest operating system. 
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>You must call <see cref="LoginInGuest"/> before calling this function.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <returns>A list of <see cref="GuestProcess"/> objects containing information about every process.</returns>
        public List<GuestProcess> ListProcessesInGuest()
        {
            IJob jobHandle = this.vmHandle.ListProcessesInGuest(0, null);
            JobWaitWithoutResults(jobHandle);

            List<object> list = VixCOMWrapper.Instance.GetProperties((IVixHandle)jobHandle, new VIX_PROPERTY[] { VIX_PROPERTY.JOB_RESULT_ITEM_NAME, VIX_PROPERTY.JOB_RESULT_PROCESS_ID, VIX_PROPERTY.JOB_RESULT_PROCESS_OWNER, VIX_PROPERTY.JOB_RESULT_PROCESS_COMMAND, VIX_PROPERTY.JOB_RESULT_PROCESS_BEING_DEBUGGED, VIX_PROPERTY.JOB_RESULT_PROCESS_START_TIME });

            List<GuestProcess> res = new List<GuestProcess>();

            int parCount = ((object[])list[0]).Length;

            // Index 0 contains the process name, 1 the process id, 2 the process owner, 3 the process command line, 4 the debugged property and 5 the process start time.
            for (int i = 0; i < parCount; i++)
                res.Add(new GuestProcess(
                    // process name
                    (string)((object[])list[0])[i],
                    // process owner
                    (string)((object[])list[2])[i],
                    // process id
                    (long)((object[])list[1])[i],
                    // process command line
                    (string)((object[])list[3])[i],
                    // is the process being debugged? (always false on Linux)
                    (bool)((object[])list[4])[i],
                    // process start time
                    new DateTime(1970, 1, 1).AddSeconds((long)((object[])list[5])[i])
                    ));

            return res;
        }

        /// <summary>
        /// This function establishes a guest operating system authentication context that can be used with guest functions for this virtual machine.
        /// </summary>
        /// <remarks>
        /// <list type="bullet">
        /// <item>This function validates the account name and password in the guest OS. You must call this function before calling functions to perform operations on the guest OS, such as those below. Otherwise you do not need to call this function.</item>
        /// <item>Logins are supported on Linux and Windows. To log in as a Windows Domain user, specify the <paramref name="userName"/> parameter in the form "domain\username".</item>
        /// <item>This function does not respect access permissions on guest operating systems Windows 95, Windows 98, and Windows ME, due to limitations of the permissions model in those operating systems.</item>
        /// <item>Other guest operating systems are not supported for login, including Solaris, FreeBSD, and Netware.</item>
        /// <item>This function does not load system environment variables. <paramref name="interactiveEnvironment"/> should be set to true to ensure that the functions <see cref="CaptureScreenImage()"/>, <see cref="OpenUrlInGuest"/>, and <see cref="RunProgramInGuest"/> work correctly.</item>
        /// <item>The following functions require that you call <see cref="LoginInGuest"/>:</item>
        /// o	<see cref="RunProgramInGuest(string, string, bool, bool, bool)"/>
        /// o	<see cref="ListProcessesInGuest"/>
        /// o	<see cref="KillProcessInGuest"/>
        /// o	<see cref="RunScriptInGuest"/>
        /// o	<see cref="OpenUrlInGuest"/>
        /// o	<see cref="CopyFileFromHostToGuest"/>
        /// o	<see cref="CopyFileFromGuestToHost"/>
        /// o	<see cref="DeleteFileInGuest"/>
        /// o	<see cref="FileExistsInGuest"/>
        /// o	<see cref="RenameFileInGuest"/>
        /// o	<see cref="CreateTempFileInGuest"/>
        /// o	<see cref="ListDirectoryInGuest"/>
        /// o	<see cref="CreateDirectoryInGuest"/>
        /// o	<see cref="DeleteDirectoryInGuest"/>
        /// o	<see cref="DirectoryExistsInGuest"/>
        /// o	<see cref="WriteVariable(string, string)"/> when writing a VIX_GUEST_ENVIRONMENT_VARIABLE value.
        /// o	<see cref="CaptureScreenImage()"/>/>
        /// <item>All guest operations for a particular <see cref="VM"/> object are done using the identity you provide to <see cref="LoginInGuest"/>. As a result, guest operations are restricted by file system privileges in the guest OS that apply to the user specified in  <see cref="LoginInGuest"/>. For example, <see cref="DeleteDirectoryInGuest"/> might fail if the user named in <see cref="LoginInGuest"/> does not have access permissions to the directory in the guest OS.</item>
        /// <item><see cref="LoginInGuest"/> changes the behavior of Vix functions to use a user account. It does not log a user into a console session on the guest OS. As a result, you might not see the user logged in from within the guest OS. Moreover, operations such as rebooting the guest do not clear the guest credentials.</item>
        /// <item>You must call <see cref="LoginInGuest"/> for each <see cref="VM"/> object that uses guest operations.</item>
        /// <item>The virtual machine must be powered on before calling this function.</item>
        /// <item>VMware Tools must be installed and running on the guest OS before calling this function. You can call <see cref="WaitForToolsInGuest"/> to wait for the tools to run.</item>
        /// <item>Once <see cref="LoginInGuest"/> has succeeded, the user session remains valid until</item>
        /// o	<see cref="LogoutFromGuest"/> is called successfully, 
        /// o	<see cref="LoginInGuest"/> is called successfully with different user credentials, 
        /// o	the virtual machine object gets destroyed 
        /// o	the client applications exits.
        /// <item>The special login type VIX_CONSOLE_USER_NAME is no longer supported.</item>
        /// <item>Calling LoginInGuest() with <paramref name="interactiveEnvironment"/> set to true can only be done when there is an interactive user logged into the guest OS. Specifically, the "interactive user" refers to the user who has logged into the guest OS through the console (for instance, the user who logged into the Windows log-in screen). The VIX user is the user whose credentials are being provided in the call to LoginInGuest(). With <paramref name="interactiveEnvironment"/> set to true, there must be an interactive user logged into the guest when the call to LoginInGuest() is made, and the VIX user must match the interactive user (they must have same account in the guest OS).</item>
        /// <item>Using <paramref name="interactiveEnvironment"/> set to true will ensure that the environment in which guest commands are executed is as close as possible to the normal environment in which a user interacts with the guest OS. With <paramref name="interactiveEnvironment"/> set to false, commands may be run in a more limited environment;</item>
        /// <item>On Linux guest operating systems, the <paramref name="interactiveEnvironment"/> set to true requires that X11 be installed and running.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="userName">The name of a user account on the guest operating system.</param>
        /// <param name="password">The password of the account identified by <paramref name="userName"/>.</param>
        /// <param name="interactiveEnvironment">True, if you want to use the interactive environment, otherwise false.</param>
        public void LoginInGuest(string userName, string password, bool interactiveEnvironment)
        {
            IJob jobHandle = this.vmHandle.LoginInGuest(userName, password, interactiveEnvironment ? VixCOM.Constants.VIX_LOGIN_IN_GUEST_REQUIRE_INTERACTIVE_ENVIRONMENT : 0, null);
            JobWaitWithoutResults(jobHandle);
        }

        /// <summary>
        /// This function removes any guest operating system authentication context created by a previous call to <see cref="LoginInGuest"/>. 
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>This function has no effect and returns success if <see cref="LoginInGuest"/> has not been called.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        public void LogoutFromGuest()
        {
            IJob jobHandle = this.vmHandle.LogoutFromGuest(null);
            JobWaitWithoutResults(jobHandle);
        }

        /// <summary>
        /// This function opens a browser window on the specified URL in the guest operating system. 
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>This function is deprecated and may be removed from future versions of the VIX API.</item>
        /// <item>This function opens the URL in the guest operating system.</item>
        /// <item>You must call <see cref="LoginInGuest"/> and pass true as the interactiveEnvironment parameter, and enable autologin on the guest operating system, before calling this function.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="url">The URL to be opened.</param>
        [Obsolete]
        public void OpenUrlInGuest(string url)
        {
            IJob jobHandle = this.vmHandle.OpenUrlInGuest(url, 0, null, null);
            JobWaitWithoutResults(jobHandle);
        }

        /// <summary>
        /// This function pauses a virtual machine. See remarks section for pause behavior when used with different operations. 
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>This stops execution of the virtual machine.</item>
        /// <item>Functions that invoke guest operations should not be called when the virtual machine is paused.</item>
        /// <item>Call <see cref="Unpause"/> to continue execution of the virtual machine.</item>
        /// <item>Calling <see cref="Reset"/>, <see cref="PowerOff"/>, and <see cref="Suspend"/> will successfully work when paused. The pause state is not preserved in a suspended virtual machine; a subsequent <see cref="PowerOn(VIX_VMPOWEROP)"/> will not remember the previous pause state.</item> 
        /// <item>Calling <see cref="BeginRecording"/> when paused is legal. The actual recording will start when the virtual machine is unpaused.</item>
        /// <item>Do not call <see cref="BeginReplay"/> when the virtual machine is paused. To do so, call <see cref="PowerOff"/> first, which will reset the pause state. After the virtual machine is powered off, you can then call <see cref="BeginReplay"/>.</item>
        /// <item>This function is not supported when using the <see cref="VIX_SERVICEPROVIDER.VMWARE_PLAYER"/> host type.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        public void Pause()
        {
            IJob jobHandle = this.vmHandle2.Pause(0, null, null);
            JobWaitWithoutResults(jobHandle);
        }

        /// <summary>
        /// This function powers off a virtual machine.
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>If you call this function while the virtual machine is powered off, the operation raises an exception with error-code <see cref="VIX_E.VM_NOT_RUNNING"/>. You can safely ignore this error.</item>
        /// <item>If you call this function while the virtual machine is suspended, the operation raises an exception with error-code <see cref="VIX_E.VM_NOT_RUNNING"/> error. The virtual machine is not powered off and remains suspended.</item>
        /// <item>The <see cref="VIX_VMPOWEROP.FROM_GUEST"/> flag will cause the function to try to power off the guest OS. This will ensure a clean shutdown of the guest. This option requires that the VMware Tools be installed and running in the guest.</item>
        /// <item>If <see cref="VIX_VMPOWEROP.NORMAL"/> is passed as the <paramref name="powerOffOptions"/> parameter, then the virtual machine will be powered off at the hardware level. Any state of the guest that has not been committed to disk will be lost.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <exception cref="ArgumentException">Thrown when <paramref name="powerOffOptions"/> is not <see cref="VIX_VMPOWEROP.NORMAL"/> or <see cref="VIX_VMPOWEROP.FROM_GUEST"/>.</exception>
        /// <param name="powerOffOptions">Must be <see cref="VIX_VMPOWEROP.NORMAL"/> or <see cref="VIX_VMPOWEROP.FROM_GUEST"/>.</param>
        public void PowerOff(VIX_VMPOWEROP powerOffOptions)
        {
            if (!(powerOffOptions == VIX_VMPOWEROP.NORMAL || powerOffOptions == VIX_VMPOWEROP.FROM_GUEST))
                throw new ArgumentException("The powerOffOption parameter can only be VIX_VMPOWEROP.NORMAL or VIX_VMPOWEROP.FROM_GUEST.");

            IJob jobHandle = this.vmHandle.PowerOff((int)powerOffOptions, null);
            JobWaitWithoutResults(jobHandle);
        }

        /// <summary>
        /// <para>Powers on a virtual machine.</para>
        /// <para>The function returns when the virtual machine has started to boot.</para>
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>In Server 1.0, when you power on a virtual machine, the virtual machine is powered on independent of a console window. If a console window is open, it remains open. Otherwise, the virtual machine is powered on without a console window.</item>
        /// <item>To display a virtual machine with a Workstation user interface, <paramref name="powerOnOptions"/> must have the <see cref="VIX_VMPOWEROP.LAUNCH_GUI"/> flag, and you must be connected to the host with the <see cref="VIX_SERVICEPROVIDER.VMWARE_WORKSTATION"/> flag. If there is an existing instance of the Workstation user interface, the virtual machine will power on in a new tab within that instance. Otherwise, a new instance of Workstation will open, and the virtual machine will power on there.</item>
        /// <item>To display a virtual machine with a Player user interface, <paramref name="powerOnOptions"/> must have the <see cref="VIX_VMPOWEROP.LAUNCH_GUI"/> flag, and you must be connected to the host with the <see cref="VIX_SERVICEPROVIDER.VMWARE_PLAYER"/> flag. A new instance of Player will always open, and the virtual machine will power on there.</item>
        /// <item>This function can also be used to resume execution of a suspended virtual machine.</item>
        /// <item>The <see cref="VIX_VMPOWEROP.LAUNCH_GUI"/> option is not supported for encrypted virtual machines; attempting to power on with this option results in an exception with error code <see cref="VIX_E.NOT_SUPPORTED"/>.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <exception cref="ArgumentException">Thrown when <paramref name="powerOnOptions"/> is not <see cref="VIX_VMPOWEROP.NORMAL"/> or <see cref="VIX_VMPOWEROP.LAUNCH_GUI"/>.</exception>
        /// <param name="powerOnOptions">Indicates which method is used to power on the VM, either <see cref="VIX_VMPOWEROP.NORMAL"/> or <see cref="VIX_VMPOWEROP.LAUNCH_GUI"/>.</param>
        public void PowerOn(VIX_VMPOWEROP powerOnOptions)
        {
            if (!(powerOnOptions == VIX_VMPOWEROP.NORMAL || powerOnOptions == VIX_VMPOWEROP.LAUNCH_GUI))
                throw new ArgumentException("The powerOnOption parameter can only be VIX_VMPOWEROP.NORMAL or VIX_VMPOWEROP.LAUNCH_GUI.");

            this.PowerOn(powerOnOptions, 0);
        }

        /// <summary>
        /// <para>Powers on a virtual machine.</para>
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>If the VMware Tools have been installed on this guest operating system, you can pass a value for the <paramref name="waitForToolsInGuestTimeout"/> parameter to determine when the guest has finished booting.</item>
        /// <item>In Server 1.0, when you power on a virtual machine, the virtual machine is powered on independent of a console window. If a console window is open, it remains open. Otherwise, the virtual machine is powered on without a console window.</item>
        /// <item>To display a virtual machine with a Workstation user interface, <paramref name="powerOnOptions"/> must have the <see cref="VIX_VMPOWEROP.LAUNCH_GUI"/> flag, and you must be connected to the host with the <see cref="VIX_SERVICEPROVIDER.VMWARE_WORKSTATION"/> flag. If there is an existing instance of the Workstation user interface, the virtual machine will power on in a new tab within that instance. Otherwise, a new instance of Workstation will open, and the virtual machine will power on there.</item>
        /// <item>To display a virtual machine with a Player user interface, <paramref name="powerOnOptions"/> must have the <see cref="VIX_VMPOWEROP.LAUNCH_GUI"/> flag, and you must be connected to the host with the <see cref="VIX_SERVICEPROVIDER.VMWARE_PLAYER"/> flag. A new instance of Player will always open, and the virtual machine will power on there.</item>
        /// <item>This function can also be used to resume execution of a suspended virtual machine.</item>
        /// <item>The <see cref="VIX_VMPOWEROP.LAUNCH_GUI"/> option is not supported for encrypted virtual machines; attempting to power on with this option results in an exception with error code <see cref="VIX_E.NOT_SUPPORTED"/>.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <exception cref="ArgumentOutOfRangeException">Thrown when <paramref name="waitForToolsInGuestTimeout"/> contains a negative value.</exception>
        /// <param name="powerOnOptions">Indicates which method is used to power on the VM, either <see cref="VIX_VMPOWEROP.NORMAL"/> or <see cref="VIX_VMPOWEROP.LAUNCH_GUI"/>.</param>
        /// <param name="waitForToolsInGuestTimeout">Indicates how long (in seconds) the function should wait until the VMware Tools are loaded in the VM.</param>
        public void PowerOn(VIX_VMPOWEROP powerOnOptions, int waitForToolsInGuestTimeout)
        {
            IJob jobHandle = this.vmHandle.PowerOn((int)powerOnOptions, null, null);
            JobWaitWithoutResults(jobHandle);

            // return if we should not wait for the VMware Tools
            if (waitForToolsInGuestTimeout == 0)
                return;

            // wrong argument specified for the timeout parameter
            if (waitForToolsInGuestTimeout < 0)
                throw new ArgumentOutOfRangeException("waitForToolsInGuestTimeout", "The waitForToolsInGuestTimeout parameter must contain a positive value.");

            // wait for the VMware Tools
            this.WaitForToolsInGuest(waitForToolsInGuestTimeout);
        }

        /// <summary>
        /// This function reads environment variables in the guest. 
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>You must call <see cref="LoginInGuest"/> before calling this function to read an environment variable.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="name">The name of the environment variable.</param>
        /// <returns>A string containing the value of the environment variable.</returns>
        public string ReadVariable(string name)
        {
            return ReadVariable((int)VixCOM.Constants.VIX_GUEST_ENVIRONMENT_VARIABLE, name);
        }

        /// <summary>
        /// This function reads variables from the virtual machine state. This includes the virtual machine configuration and VMware "Guest Variables". 
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>You do not have to call <see cref="LoginInGuest"/> to use this function to read a <see cref="VIX_VM.GUEST_VARIABLE"/> or a <see cref="VIX_VM.CONFIG_RUNTIME_ONLY"/> value.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="variableType">The type of variable to read.</param>
        /// <param name="name">The name of the variable.</param>
        /// <returns>A string containing the value of the variable.</returns>
        public string ReadVariable(VIX_VM variableType, string name)
        {
            return ReadVariable((int)variableType, name);
        }

        /// <summary>
        /// This function reads variables from the virtual machine state. This includes the virtual machine configuration, environment variables in the guest, and VMware "Guest Variables". 
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>You must call <see cref="LoginInGuest"/> before calling this function to read an environment variable.</item>
        /// <item>You do not have to call <see cref="LoginInGuest"/> to use this function to read a <see cref="VIX_VM.GUEST_VARIABLE"/> or a <see cref="VIX_VM.CONFIG_RUNTIME_ONLY"/> value.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="variableType">The type of variable to read. The currently supported values are: <see cref="VIX_VM.GUEST_VARIABLE"/>, <see cref="VIX_VM.CONFIG_RUNTIME_ONLY"/>, VIX_GUEST_ENVIRONMENT_VARIABLE.</param>
        /// <param name="name">The name of the variable.</param>
        /// <returns>A string containing the value of the variable.</returns>
        private string ReadVariable(int variableType, string name)
        {
            IJob jobHandle = this.vmHandle.ReadVariable((int)variableType, name, 0, null);

            object results = null;

            ulong err = jobHandle.Wait(new VIX_PROPERTY[] { VIX_PROPERTY.JOB_RESULT_VM_VARIABLE_STRING }, ref results);

            VixCOMWrapper.Instance.CheckForError(err);

            return (string)((object[])results)[0];
        }

        /// <summary>
        /// This function removes a shared folder in the virtual machine. 
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>It is not necessary to call <see cref="LoginInGuest"/> before calling this function.</item>
        /// <item>Shared folders are not supported for the following guest operating systems: Windows ME, Windows 98, Windows 95, Windows 3.x, and DOS.</item>
        /// <item>In this release, this function requires the virtual machine to be powered on with VMware Tools installed.</item>
        /// <item>Depending on the behavior of the guest operating system, when removing shared folders, there might be a delay before the shared folder is no longer visible to programs running within the guest operating system and to functions such as <see cref="FileExistsInGuest"/>.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="shareName">Specifies the guest pathname of the shared folder to delete.</param>
        public void RemoveSharedFolder(string shareName)
        {
            IJob jobHandle = this.vmHandle.RemoveSharedFolder(shareName, 0, null);
            JobWaitWithoutResults(jobHandle);
        }

        /// <summary>
        /// This function deletes all saved states for the specified snapshot.
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>This function deletes all saved states for the specified snapshot. If the snapshot was based on another snapshot, the base snapshot becomes the new root snapshot.</item>
        /// <item>The VMware Server release of the VIX API can manage only a single snapshot for each virtual machine. A virtual machine imported from another VMware product can have more than one snapshot at the time it is imported. In that case, you can delete only a snapshot subsequently added using the VIX API.</item>
        /// <item>Starting in VMware Workstation 6.5, snapshot operations are allowed on virtual machines that are part of a team. Previously, this operation failed with error code <see cref="VIX_PROPERTY.VM_IN_VMTEAM"/>. Team members snapshot independently so they can have different and inconsistent snapshot states.</item>
        /// <item>This function is not supported when using the <see cref="VIX_SERVICEPROVIDER.VMWARE_PLAYER"/> host type.</item>
        /// <item>If the virtual machine is open and powered off in the UI, this function may close the virtual machine in the UI before deleting the snapshot.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="snapshot">A <see cref="Snapshot"/> object representing the snapshot to remove. A virtual machine's snapshots can be accessed through <see cref="GetRootSnapshot"/>.</param>
        /// <param name="deleteChildSnapshots">If true, removes snapshots that are children of the given snapshot. Otherwise, child snapshots are preserved.</param>
        public void RemoveSnapshot(Snapshot snapshot, bool deleteChildSnapshots)
        {
            IJob jobHandle = this.vmHandle.RemoveSnapshot(snapshot.Handle, deleteChildSnapshots ? VixCOM.Constants.VIX_SNAPSHOT_REMOVE_CHILDREN : 0, null);
            JobWaitWithoutResults(jobHandle);
        }

        /// <summary>
        /// This function renames a file or directory in the guest operating system.
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>You must call <see cref="LoginInGuest"/> before calling this function.</item>
        /// <item>Only absolute paths should be used for files in the guest; the resolution of relative paths is not specified.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="oldName">The path to the file to be renamed.</param>
        /// <param name="newName">The path to the new file.</param>
        public void RenameFileInGuest(string oldName, string newName)
        {
            IJob jobHandle = this.vmHandle.RenameFileInGuest(oldName, newName, 0, null, null);
            JobWaitWithoutResults(jobHandle);
        }

        /// <summary>
        /// This function resets a virtual machine.
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>If you pass <see cref="VIX_VMPOWEROP.NORMAL"/> as the options, this function is the equivalent of pressing the reset button on a physical machine.</item>
        /// <item>The <see cref="VIX_VMPOWEROP.FROM_GUEST"/> flag will cause the function to try to reset the guest OS. This will ensure a clean shutdown of the guest. This option requires that the VMware Tools be installed and running in the guest.</item>
        /// <item>If the virtual machine is not powered on when you call this function, it raises an exception.</item>
        /// <item>After reset, you must call <see cref="WaitForToolsInGuest"/> before executing guest operations or querying guest properties. </item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <exception cref="ArgumentException">Thrown when <paramref name="resetOptions"/> is not <see cref="VIX_VMPOWEROP.NORMAL"/> or <see cref="VIX_VMPOWEROP.FROM_GUEST"/>.</exception>
        /// <param name="resetOptions">Indicates which method is used to reset the VM. Must be <see cref="VIX_VMPOWEROP.NORMAL"/> or <see cref="VIX_VMPOWEROP.FROM_GUEST"/>.</param>
        public void Reset(VIX_VMPOWEROP resetOptions)
        {
            if (!(resetOptions == VIX_VMPOWEROP.NORMAL || resetOptions == VIX_VMPOWEROP.FROM_GUEST))
                throw new ArgumentException("The resetOptions parameter can only be VIX_VMPOWEROP.NORMAL or VIX_VMPOWEROP.FROM_GUEST.");

            IJob jobHandle = this.vmHandle.Reset((int)resetOptions, null);
            JobWaitWithoutResults(jobHandle);
        }

        /// <summary>
        /// Restores the virtual machine to the state when the specified snapshot was created. 
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>Restores the virtual machine to the state when the specified snapshot was created. This function can power on, power off, or suspend a virtual machine. The resulting power state reflects the power state when the snapshot was created.</item>
        /// <item>When you revert a powered on virtual machine and want it to display in the Workstation user interface, <paramref name="options"/> must have the <see cref="VIX_VMPOWEROP.LAUNCH_GUI"/> flag, unless the <see cref="VIX_VMPOWEROP.SUPPRESS_SNAPSHOT_POWERON"/> is used.</item>
        /// <item>The <see cref="VIX_PROPERTY.VM_TOOLS_STATE"/> property of the virtual machine is undefined after the snapshot is reverted.</item>
        /// <item>Starting in VMware Workstation 6.5, snapshot operations are allowed on virtual machines that are part of a team. Previously, this operation failed with error code <see cref="VIX_PROPERTY.VM_IN_VMTEAM"/>. Team members snapshot independently so they can have different and inconsistent snapshot states.</item>
        /// <item>This function is not supported when using the <see cref="VIX_SERVICEPROVIDER.VMWARE_PLAYER"/> host type.</item>
        /// <item>If the virtual machine is open and powered off in the UI, this function now closes the virtual machine in the UI before reverting to the snapshot. To refresh this property, you must wait for tools in the guest.</item>
        /// <item>After reverting to a snapshot, you must call <see cref="WaitForToolsInGuest"/> before executing guest operations or querying guest properties. </item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="snapshot">A <see cref="Snapshot"/> object representing the snapshot to revert to. A virtual machine's snapshots can be accessed through <see cref="GetRootSnapshot"/>.</param>
        /// <param name="options">Any applicable <see cref="VIX_VMPOWEROP"/>. If the virtual machine was powered on when the snapshot was created, then this will determine how the virtual machine is powered back on. To prevent the virtual machine from being powered on regardless of the power state when the snapshot was created, use the <see cref="VIX_VMPOWEROP.SUPPRESS_SNAPSHOT_POWERON"/> flag. <see cref="VIX_VMPOWEROP.SUPPRESS_SNAPSHOT_POWERON"/> is mutually exclusive to all other <see cref="VIX_VMPOWEROP"/> options.</param>
        public void RevertToSnapshot(Snapshot snapshot, VIX_VMPOWEROP options)
        {
            IJob jobHandle = this.vmHandle.RevertToSnapshot(snapshot.Handle, (int)options, null, null);
            JobWaitWithoutResults(jobHandle);
        }

        /// <summary>
        /// This function runs a program in the guest operating system. The program must be stored on a file system available to the guest before calling this function. 
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>The current working directory for the program in the guest is not defined. Absolute paths should be used for files in the guest, including <paramref name="guestProgramName"/> and any command-line arguments.</item>
        /// <item>You must call <see cref="LoginInGuest"/> before calling this function.</item>
        /// <item>If the program to run in the guest is intended to be visible to the user in the guest, such as an application with a graphical user interface, you must call <see cref="LoginInGuest"/> and pass true as the interactiveEnvironment parameter before calling this function. This will ensure that the program is run within a graphical session that is visible to the user.</item>
        /// <item>If the <paramref name="returnImmediately"/> parameter is false, this function will return when the program exits in the guest operating system. Alternatively, you can pass true as the value of the <paramref name="returnImmediately"/> parameter, and this function returns as soon as the program starts in the guest.</item>
        /// <item>For Windows guest operating systems, when running a program with a graphical user interface, you can pass true as the <paramref name="activateWindow"/> parameter. This option will ensure that the application's window is visible and not minimized on the guest's screen. This has no effect on Linux guest operating systems.</item>
        /// <item>On a Linux guest operating system, if you are running a program with a graphical user interface, it must know what X Windows display to use, for example host:0.0, so it can make the program visible on that display. Do this by passing the -display argument to the program, if it supports that argument, or by setting the DISPLAY environment variable on the guest. See documentation on <see cref="WriteVariable(string, string)"/>.</item>
        /// <item>Depending on the behavior of the guest operating system, there may be a short delay after the job completes before the process is visible in the guest operating system.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="guestProgramName">The path name of an executable file on the guest operating system</param>
        /// <param name="commandLineArgs">A string to be passed as command line arguments to the executable identified by guestProgramName</param>
        /// <param name="returnImmediately">If true, the function returns as soon as the program starts in the guest. If false, the function will return when the program exits in the guest operating system.</param>
        /// <param name="activateWindow">This option will ensure that the application's window is visible and not minimized on the guest's screen. Only available on Windows guest operating systems.</param>
        /// <param name="getProcessID">If true, the function gets the process id also. Otherwise it only gets the elapsed time and the exit code of the program. Note: if the guest has an older version of Tools (those released with Workstation 6 and earlier) and <paramref name="returnImmediately"/> is true, then the process ID will not be returned from the guest, so attempting to access this property will result in an exception with error-code <see cref="VIX_E.UNRECOGNIZED_PROPERTY"/> being raised.</param>
        /// <returns>An <see cref="Object"/> array containing information about the program. If <paramref name="getProcessID"/> is true, Index 0 will contain the process id, 1 the process elapsed time and 2 the process exit code. If <paramref name="getProcessID"/> is false, only the latter two will be available. However, if <paramref name="returnImmediately"/> is true, they will be both 0.</returns>
        public object[] RunProgramInGuest(string guestProgramName, string commandLineArgs, bool returnImmediately, bool activateWindow, bool getProcessID)
        {
            int options = 0;

            if (returnImmediately)
                options |= VixCOM.Constants.VIX_RUNPROGRAM_RETURN_IMMEDIATELY;

            if (activateWindow)
                options |= VixCOM.Constants.VIX_RUNPROGRAM_ACTIVATE_WINDOW;

            IJob jobHandle = this.vmHandle.RunProgramInGuest(guestProgramName, commandLineArgs, options, null, null);
            JobWaitWithoutResults(jobHandle);

            VIX_PROPERTY[] propertiesToRetrieve;

            if (getProcessID)
                propertiesToRetrieve = new VIX_PROPERTY[] { VIX_PROPERTY.JOB_RESULT_PROCESS_ID, VIX_PROPERTY.JOB_RESULT_GUEST_PROGRAM_ELAPSED_TIME, VIX_PROPERTY.JOB_RESULT_GUEST_PROGRAM_EXIT_CODE };
            else
                propertiesToRetrieve = new VIX_PROPERTY[] { VIX_PROPERTY.JOB_RESULT_GUEST_PROGRAM_ELAPSED_TIME, VIX_PROPERTY.JOB_RESULT_GUEST_PROGRAM_EXIT_CODE };

            List<object> temp = VixCOMWrapper.Instance.GetProperties((IVixHandle)jobHandle, propertiesToRetrieve);

            return temp.ToArray();
        }

        /// <summary>
        /// This function runs a script in the guest operating system. 
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>The current working directory for the script executed in the guest is not defined. Absolute paths should be used for files in the guest, including the path to the interpreter, and any files referenced in the script text.</item>
        /// <item>You must call <see cref="LoginInGuest"/> before calling this function.</item>
        /// <item>If the <paramref name="returnImmediately"/> parameter is false, this function will return when the program exits in the guest operating system. Alternatively, you can pass true as the value of the <paramref name="returnImmediately"/> parameter, and this function returns as soon as the program starts in the guest.</item>
        /// <item>Depending on the behavior of the guest operating system, there may be a short delay after the job completes before the process is visible in the guest operating system.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="interpreter">The path to the script interpreter.</param>
        /// <param name="scriptText">The text of the script.</param>
        /// <param name="returnImmediately">If true, the function returns as soon as the program starts in the guest. If false, the function will return when the program exits in the guest operating system.</param>
        /// <param name="getProcessID">If true, the function gets the process id also. Otherwise it only gets the elapsed time and the exit code of the program. Note: if the guest has an older version of Tools (those released with Workstation 6 and earlier) and <paramref name="returnImmediately"/> is true, then the process ID will not be returned from the guest, so attempting to access this property will result in an exception with error-code <see cref="VIX_E.UNRECOGNIZED_PROPERTY"/> being raised.</param>      
        /// <returns>An <see cref="Object"/> array containing information about the program. If <paramref name="getProcessID"/> is true, Index 0 will contain the process id, 1 the process elapsed time and 2 the process exit code. If <paramref name="getProcessID"/> is false, only the latter two will be available. However, if <paramref name="returnImmediately"/> is true, they will be both 0.</returns>
        public object[] RunScriptInGuest(string interpreter, string scriptText, bool returnImmediately, bool getProcessID)
        {
            IJob jobHandle = this.vmHandle.RunScriptInGuest(interpreter, scriptText, returnImmediately ? VixCOM.Constants.VIX_RUNPROGRAM_RETURN_IMMEDIATELY : 0, null, null);
            JobWaitWithoutResults(jobHandle);

            VIX_PROPERTY[] propertiesToRetrieve;

            if (getProcessID)
                propertiesToRetrieve = new VIX_PROPERTY[] { VIX_PROPERTY.JOB_RESULT_PROCESS_ID, VIX_PROPERTY.JOB_RESULT_GUEST_PROGRAM_ELAPSED_TIME, VIX_PROPERTY.JOB_RESULT_GUEST_PROGRAM_EXIT_CODE };
            else
                propertiesToRetrieve = new VIX_PROPERTY[] { VIX_PROPERTY.JOB_RESULT_GUEST_PROGRAM_ELAPSED_TIME, VIX_PROPERTY.JOB_RESULT_GUEST_PROGRAM_EXIT_CODE };

            List<object> temp = VixCOMWrapper.Instance.GetProperties((IVixHandle)jobHandle, propertiesToRetrieve);

            return temp.ToArray();
        }

        /// <summary>
        /// This function modifies the state of a shared folder mounted in the virtual machine. 
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>This function modifies the state flags of an existing shared folder.</item>
        /// <item>If the shared folder specified by <paramref name="shareName"/> does not exist before calling this function, the function will raise an exception with error-code <see cref="VIX_E.NOT_FOUND"/>.</item>
        /// <item>It is not necessary to call <see cref="LoginInGuest"/> before calling this function.</item>
        /// <item>Shared folders are not supported for the following guest operating systems: Windows ME, Windows 98, Windows 95, Windows 3.x, and DOS.</item>
        /// <item>In this release, this function requires the virtual machine to be powered on with VMware Tools installed.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="shareName">Specifies the name of the shared folder.</param>
        /// <param name="hostPathName">Specifies the host path of the shared folder.</param>
        /// <param name="writeAccess">Specifies whether the share is write-enabled (true) or not (false).</param>
        public void SetSharedFolderState(string shareName, string hostPathName, bool writeAccess)
        {
            IJob jobHandle = this.vmHandle.SetSharedFolderState(shareName, hostPathName, writeAccess ? VixCOM.Constants.VIX_SHAREDFOLDER_WRITE_ACCESS : 0, null);
            JobWaitWithoutResults(jobHandle);
        }

        /// <summary>
        /// This function suspends a virtual machine. 
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>If the virtual machine is not powered on when you call this function, the function raises an exception.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        public void Suspend()
        {
            IJob jobHandle = this.vmHandle.Suspend(0, null);
            JobWaitWithoutResults(jobHandle);
        }

        /// <summary>
        /// This function continues execution of a paused virtual machine. 
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>This operation continues execution of a virtual machine that was stopped using <see cref="Pause"/>.</item>
        /// <item>Refer to <see cref="Pause"/> for pause/unpause behavior with different operations.</item>
        /// <item>This function is not supported when using the <see cref="VIX_SERVICEPROVIDER.VMWARE_PLAYER"/> host type.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        public void Unpause()
        {
            IJob jobHandle = this.vmHandle2.Unpause(0, null, null);
            JobWaitWithoutResults(jobHandle);
        }

        /// <summary>
        /// Upgrades the virtual hardware version of the virtual machine to match the version of the VIX library. This has no effect if the virtual machine is already at the same version or at a newer version than the VIX library. 
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>The virtual machine must be powered off to do this operation.</item>
        /// <item>When the VM is already up-to-date, the function will throw an exception with error-code <see cref="VIX_E.VM_ALREADY_UP_TO_DATE"/>.</item>
        /// <item>This function is not supported when using the <see cref="VIX_SERVICEPROVIDER.VMWARE_PLAYER"/> host type.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        public void UpgradeVirtualHardware()
        {
            IJob jobHandle = this.vmHandle.UpgradeVirtualHardware(0, null);
            JobWaitWithoutResults(jobHandle);
        }

        /// <summary>
        /// This function waits until VMware Tools has successfully started in the guest operating system. VMware Tools is a collection of services that run in the guest. 
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>VMware Tools must be installed and running for some Vix functions to operate correctly. If VMware Tools is not installed in the guest operating system, or if the virtual machine is not powered on, this function raises an exception.</item>
        /// <item>The <see cref="VIX_PROPERTY.VM_TOOLS_STATE"/> property of the virtual machine is undefined until <see cref="WaitForToolsInGuest"/> reports that VMware Tools is running.</item>
        /// <item>This function should be called after calling any function that resets or reboots the state of the guest operating system, but before calling any functions that require VMware Tools to be running. Doing so assures that VMware Tools are once again up and running. Functions that reset the guest operating system in this way include:</item>
        /// o	<see cref="PowerOn(VIX_VMPOWEROP)"/>
        /// o	<see cref="Reset"/>
        /// o	<see cref="RevertToSnapshot"/>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="timeoutInSeconds">The timeout in seconds. If VMware Tools has not started by this time, the function raises an exception. If the value of this argument is zero or negative, then there will be no timeout.</param>
        public void WaitForToolsInGuest(int timeoutInSeconds)
        {
            IJob jobHandle = this.vmHandle.WaitForToolsInGuest(timeoutInSeconds, null);
            JobWaitWithoutResults(jobHandle);
        }

        /// <summary>
        /// This function writes environment variables to the virtual machine.
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>You must call <see cref="LoginInGuest"/> before calling this function to write environment variables.</item>
        /// <item>Do not use the slash '/' character in a variable name; doing so produces an exception with error-code <see cref="VIX_E.INVALID_ARG"/>.</item>
        /// <item>Do not use the equal '=' character in the <paramref name="valueName"/> parameter; doing so produces an exception with error-code <see cref="VIX_E.INVALID_ARG"/>.</item>        
        /// <item>On Linux guests, you must login as root to change environment variables.</item>
        /// <item>On Windows Vista guests, you must turn off User Account Control (UAC) in Control Panel > User Accounts > User Accounts > Turn User Account on or off, in order for this function to work.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="valueName">The name of the environment variable.</param>
        /// <param name="value">The value of the environment variable to be written.</param>
        public void WriteVariable(string valueName, string value)
        {
            WriteVariable((int)VixCOM.Constants.VIX_GUEST_ENVIRONMENT_VARIABLE, valueName, value);
        }

        /// <summary>
        /// This function writes variables to the virtual machine state. This includes the virtual machine configuration and VMware "Guest Variables". 
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>The <see cref="VIX_VM.CONFIG_RUNTIME_ONLY"/> variable type is not supported on ESX hosts.</item>
        /// <item>You do not have to call <see cref="LoginInGuest"/> to use this function to write a <see cref="VIX_VM.GUEST_VARIABLE"/> or a <see cref="VIX_VM.CONFIG_RUNTIME_ONLY"/> value.</item>
        /// <item>Do not use the slash '/' character in a variable name; doing so produces an exception with error-code <see cref="VIX_E.INVALID_ARG"/>.</item>
        /// <item>Do not use the equal '=' character in the <paramref name="valueName"/> parameter; doing so produces an exception with error-code <see cref="VIX_E.INVALID_ARG"/>.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="variableType">The type of variable to write. The currently supported values are: <see cref="VIX_VM.GUEST_VARIABLE"/> and <see cref="VIX_VM.CONFIG_RUNTIME_ONLY"/>.</param>
        /// <param name="valueName">The name of the variable.</param>
        /// <param name="value">The value to be written.</param>
        public void WriteVariable(VIX_VM variableType, string valueName, string value)
        {
            WriteVariable((int)variableType, valueName, value);
        }

        /// <summary>
        /// This function writes variables to the virtual machine state. This includes the virtual machine configuration, environment variables in the guest, and VMware "Guest Variables". 
        /// </summary>
        /// <remarks>
        /// <list type="bullet"> 
        /// <item>The <see cref="VIX_VM.CONFIG_RUNTIME_ONLY"/> variable type is not supported on ESX hosts.</item> 
        /// <item>You must call <see cref="LoginInGuest"/> before calling this function to write a VIX_GUEST_ENVIRONMENT_VARIABLE value. You do not have to call <see cref="LoginInGuest"/> to use this function to write a <see cref="VIX_VM.GUEST_VARIABLE"/> or a <see cref="VIX_VM.CONFIG_RUNTIME_ONLY"/> value.</item>
        /// <item>Do not use the slash '/' character in a variable name; doing so produces an exception with error-code <see cref="VIX_E.INVALID_ARG"/>.</item>
        /// <item>Do not use the equal '=' character in the <paramref name="valueName"/> parameter; doing so produces an exception with error-code <see cref="VIX_E.INVALID_ARG"/>.</item>
        /// <item>On Linux guests, you must login as root to change environment variables (when variable type is VIX_GUEST_ENVIRONMENT_VARIABLE) otherwise it produces an exception with error-code <see cref="VIX_E.GUEST_USER_PERMISSIONS"/>.</item>
        /// <item>On Windows Vista guests, when variable type is VIX_GUEST_ENVIRONMENT_VARIABLE, you must turn off User Account Control (UAC) in Control Panel > User Accounts > User Accounts > Turn User Account on or off, in order for this function to work.</item>
        /// </list>
        /// </remarks>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="variableType">The type of variable to write. The currently supported values are: <see cref="VIX_VM.GUEST_VARIABLE"/>, <see cref="VIX_VM.CONFIG_RUNTIME_ONLY"/> and VIX_GUEST_ENVIRONMENT_VARIABLE.</param>
        /// <param name="valueName">The name of the variable.</param>
        /// <param name="value">The value to be written.</param>
        private void WriteVariable(int variableType, string valueName, string value)
        {
            IJob jobHandle = this.vmHandle.WriteVariable((int)variableType, valueName, value, 0, null);
            JobWaitWithoutResults(jobHandle);
        }
        #endregion

        #region Info-Classes
        /// <summary>
        /// Represents information about a file.
        /// </summary>
        public class GuestFileInfo
        {
            /// <summary>
            /// Initializes a new instance of the GuestFileInfo class.
            /// </summary>
            /// <param name="fileSize">The file size as a 64-bit integer.</param>
            /// <param name="modificationDate">The modification time of the file or directory.</param>
            /// <param name="fileAttributes">Indicates if the file is a directory or a symbolic link.</param>
            public GuestFileInfo(long fileSize, DateTime modificationDate, VIX_FILE_ATTRIBUTES fileAttributes)
            {
                this.FileSize = fileSize;
                this.ModificationDate = modificationDate;
                this.FileAttributes = fileAttributes;
            }

            /// <summary>
            /// Gets the file size as a 64-bit integer. This is 0 for directories.
            /// </summary>
            public long FileSize { get; private set; }
            /// <summary>
            /// Gets the modification time of the file or directory.
            /// </summary>
            public DateTime ModificationDate { get; private set; }
            /// <summary>
            /// Gets a value indicating if the file is a directory or a symbolic link.
            /// </summary>
            public VIX_FILE_ATTRIBUTES FileAttributes { get; private set; }
        }

        /// <summary>
        /// Represents a process running in a guest virtual machine.
        /// </summary>
        public class GuestProcess
        {
            /// <summary>
            /// Initializes a new instance of the GuestProcess class.
            /// </summary>
            /// <param name="name">The process name.</param>
            /// <param name="owner">The process owner.</param>
            /// <param name="id">The process id.</param>
            /// <param name="commandLine">The process command line</param>
            /// <param name="beingDebugged"><c>True</c> if the process is being debugged; otherwise <c>false</c>.</param>
            /// <param name="startTime">The start time.</param>
            public GuestProcess(string name, string owner, long id, string commandLine, bool beingDebugged, DateTime startTime)
            {
                this.Name = name;
                this.Owner = owner;
                this.Id = id;
                this.CommandLine = commandLine;
            }

            /// <summary>
            /// Gets the name of the process.
            /// </summary>
            public string Name { get; private set; }
            /// <summary>
            /// Gets the owner of the process.
            /// </summary>
            public string Owner { get; private set; }
            /// <summary>
            /// Gets the id of the process.
            /// </summary>
            public long Id { get; private set; }
            /// <summary>
            /// Gets the command line of the process.
            /// </summary>
            public string CommandLine { get; private set; }
        }

        /// <summary>
        /// Represents a file or directory.
        /// </summary>
        public class GuestFileOrDirectory
        {
            /// <summary>
            /// Initializes a new instance of the FileOrDirectory class.
            /// </summary>
            /// <param name="name">The name of the file or directory.</param>
            /// <param name="modificationDate">The modification date of the file or directory.</param>
            /// <param name="isDirectory">Indicates wheter this instance represents a directory or not.</param>
            public GuestFileOrDirectory(string name, DateTime modificationDate, bool isDirectory)
            {
                this.Name = name;
                this.ModificationDate = modificationDate;
                this.IsDirectory = isDirectory;
            }

            /// <summary>
            /// Gets the name of the file or directory.
            /// </summary>
            public string Name { get; private set; }
            /// <summary>
            /// Gets the modification date of the file or directory.
            /// </summary>
            public DateTime ModificationDate { get; private set; }
            /// <summary>
            /// Gets a value indicating wheter this instance represents a directory or not.
            /// </summary>
            public bool IsDirectory { get; private set; }
        }
        #endregion

        #region Private functions
        /// <summary>
        /// Waits for the job to complete without checking the results.
        /// </summary>
        /// <exception cref="VixException">Thrown when a VIX-API function returns an error.</exception>
        /// <param name="jobHandle">An IJob handle to the job.</param>
        private void JobWaitWithoutResults(IJob jobHandle)
        {
            ulong err = jobHandle.WaitWithoutResults();

            VixCOMWrapper.Instance.CheckForError(err);
        }
        #endregion
    }
}
